package com.rpay.web.interceptor;

import com.rpay.common.enums.PcsResultCode;
import com.rpay.common.exception.SecurityException;
import com.rpay.web.interceptor.authentic.AccessControl;
import com.rpay.web.interceptor.authentic.AccessControlType;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

/**
 * Title：
 * Description
 *
 * @author fxg06 on 2018/4/19
 * @version 1.0
 */
@Component
public class AccessControlInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        boolean ret = true;
        if (handler instanceof HandlerMethod) {
            TreeMap<AccessControlType, String[]> types = new TreeMap<>(Comparator.comparing(AccessControlType::order));

            AccessControl cusAnn = ((HandlerMethod) handler).getBeanType().getAnnotation(AccessControl.class);
            if (cusAnn != null) {
                this.putTypes(types, cusAnn);
            }
            AccessControl methodAnn = ((HandlerMethod) handler).getMethodAnnotation(AccessControl.class);
            if (methodAnn != null) {
                this.putTypes(types, methodAnn);
            }

            Iterator<Map.Entry<AccessControlType, String[]>> it = types.entrySet().iterator();
            while (it.hasNext()) {
                if (!checkType(it.next(), request)) {
                    ret = false;
                    break;
                }
            }
        }
        if (ret) {
            return super.preHandle(request, response, handler);
        } else {
            throw new SecurityException(PcsResultCode.SECURITY_AUTHORIZE);
        }
    }

    /**
     * 判断 请求 合法性
     * @param map
     * @param request
     * @return
     */
    private boolean checkType(Map.Entry<AccessControlType, String[]> map, HttpServletRequest request) {
        AccessControlType type = map.getKey();
        return type.getBaseAccessControl().authorize(request);
    }


    private void putTypes(TreeMap<AccessControlType, String[]> types, AccessControl control) {
        AccessControlType[] type = control.type();
        String[] value = control.value();
        for (int i = 0; i < type.length; i++) {
            types.put(type[i], value);
        }
    }
}
